/*********************************************************************
 * Copyright (C) 2013 Bert Havinga
 * Inspired by the Railuino idea of Joerg Pleumann
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * LICENSE file for more details.
 */

#ifndef railuino__h
#define railuino__h

#include <Arduino.h>
#include <Printable.h>

// ===================================================================
// === Board detection ===============================================
// ===================================================================

#if defined(__AVR_ATmega328P__)
#define __UNO__ 1
#define __BOARD__ "Arduino Uno"
#elif defined(__AVR_ATmega32U4__)
#define __LEONARDO__ 1
#define __BOARD__ "Arduino Leonardo"
#elif defined(__AVR_ATmega2560__)
#define __MEGA__ 1
#define __BOARD__ "Arduino Mega"
#else
#error Unsupported board. Please adjust library.
#endif

// ===================================================================
// === Common definitions ============================================
// ===================================================================

/**
 * Version of Railuino library and required connection box software.
 */
#define RAILUINO_VERSION 0x005A // 0.90
#define TRACKBOX_VERSION 0x0127 // 1.39

/**
 * Constants for protocol base addresses.
 */
#define ADDR_ACC_MM2 0x2FFF // MM2 magnetic accessory
#define ADDR_ACC_DCC 0x3800 // DCC magnetic accessory

#define MAX_REPORTER 14     // MAX NUMBER OF REPORTERS IN A CHAIN

#define DATA  7	// data pin 3 on 4014       was a0
#define CLOCK  5	// clock pin 8 on 4014
#define LOAD  6	//This PE or P/S (pin 9, 4014)
#define RESET  4	// not used for edits reporters

#define TIME  6 //6 microsecond
#define LED  13 //LED output


/**
 * Represents a message going through the Marklin CAN bus. More or
 * less a beautified version of the real CAN message. You normally
 * don't need to use this unless you want to experiment with the
 * protocol or extend the library. See the Marklin protocol
 * documentation for details. The TrackMessage is a Printable, so
 * it can be directly used in Serial.println(), for instance. It
 * can also be converted from a String.
 */
class TrackMessage : public Printable {

  public:

  /**
   * The priority number.
   */
  byte prio;

  /**
   * The command number.
   */
  byte command;
  
  /**
   * The hash that is used for avoiding device/message collisions.
   */
  word hash;

  /**
   * Whether this is a response to a request.
   */
  boolean response;

  /**
   * The number of data bytes in the payload.
   */
  byte length;

  /**
   * The actual message data bytes.
   */
  byte data[8];

  /**
   * Clears the message, setting all values to zero. Provides for
   * easy recycling of TrackMessage objects.
   */
  void clear();
  
  byte tx_msg[13];

  /**
   * Prints the message to the given Print object, which could be a
   * Serial object, for instance. The message format looks like this
   *
   * HHHH R CC L DD DD DD DD DD DD DD DD
   *
   * with all numbers being hexadecimals and the data bytes being
   * optional beyond what the message length specifies. Exactly one
   * whitespace is inserted between different fields as a separator.
   */
  virtual size_t printTo(Print &p) const;

  /**
   * Parses the message from the given String. Returns true on
   * success, false otherwise. The message must have exactly the
   * format that printTo creates. This includes each and every
   * whitespace. If the parsing fails the state of the object is
   * undefined afterwards, and a clear() is recommended.
   */
  boolean parseFrom(String &s);

  /**
   * Print message readable to serial port
   * used for debug
   */        
  void printmessage();
 

  /**
   * sends serial CAN message
   */     
  void sendmessage();

  /**
   * returns status of a 16 bit reporter
   * no range checks at this moment
   */     
//  void reporterPolling(int nr_reporters);
  
};

// ===================================================================
// === TrackReporterS88 ==============================================
// ===================================================================

/**
 * Implements the S88 bus protocol for reporting the state of tracks.
 * S88 is basically a long shift register where each bit corresponds
 * to a single contact on the track. Flip-flops on each S88 board make
 * sure activations are stored, so it is not necessary to query a
 * contact at the exact time it is activated. This implementation
 * allows a maximum of 512 bits or 32 full-width (16 bit) S88 boards.
 * The S88 standard recommends a maximum of 30 boards, so we should be
 * on the safe side.
 */
class TrackReporterS88 {

  private:

  /**
   * The number of reporters available.
   */
//  volatile int mSize;


//  boolean mS88IntEna;

  /**
   * The most recent contact values we know.
   */ 
  volatile byte mSwitches[MAX_REPORTER+1];

  /**
   * The previous contact values we know.
   */ 
  volatile byte mPrevSwitches[64];


  /**
   * Shows if contact is enabled for reporter event.
   */ 
  volatile byte mEventSwitches[64];

  int mSize;
  
  public:


  /**
   * Creates a new TrackReporter 
   * programs the IO from the arduino
   */   
  TrackReporterS88(boolean debug);

  volatile byte refreshCount;
  /**
   * read the reporters to the array
   */      
  void readreporters(int nr_of_rep);

  /**
   * Probes the S88 bus for the number of connected reporters
   *   with the given number of modules
   * being attached. While this value can be safely set to the
   * maximum of 32, it makes sense to specify the actual number,
   * since this speeds up reporting. The method assumes 16 bit
   * modules. If you use 8 bit modules instead (or both) you need
   * to do the math yourself.
   */        
  byte ProbeBus(int modules);

  
  /**
   * Reads the current state of all contacts into the TrackReporter
   * and clears the flip-flops on all S88 boards. Call this method
   * periodically to have up-to-date values.
   */
  void refresh();

  /**
   * Returns the state of an individual contact. Valid index values
   * are 1 to 512.
   */
  boolean getValue(int index);

  /**
   * Returns the previous state of an individual contact. no Validation index values
   * are 1 to 512.
   */
  boolean getprevValue(int index);

  /**
   * Enable a reporter contact from eventhandling
   */
  boolean setEventSwitches(int index);
  
  /**
   * Clear a reporter contact from eventhandling
   */
   boolean clrEventSwitches(int index);

  /**
   * Enable all reporter contacts for eventhandling
   * up to the parameter   
   */
   
   void setEventReporters(int index);
        
  /**
   * Returns the state of a all questioned decoder contacts. Valid index values
   * are 0 - 63.
   */
  byte getDecoder(int index);

  /**
   * Returns the previous state of a all questioned decoder contacts. Valid index values
   * are 0 - 63.
   */
  byte getPrevDecoder(int index);

};


#endif
